package org.csu.demo.nettydemo.netty;

import com.google.gson.Gson;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.ImmediateEventExecutor;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

// 会话组管理
public final class SessionGroup {
    // 单例模式
    private static SessionGroup singleInstance = new SessionGroup ();
    // 组的映射，线程安全
    private ConcurrentHashMap<String, ChannelGroup> groupMap = new ConcurrentHashMap<>();
    // 新增：在线人数统计（不影响原有 groupMap）
    private final ConcurrentHashMap<String, AtomicInteger> groupOnline = new ConcurrentHashMap<>(); // 群组人数
    private final AtomicInteger globalOnline = new AtomicInteger (0); // 全局人数（可选）
    // 新增：存储每个聊天室的聊天记录
    private final ConcurrentHashMap<String, List<Map<String, String>>> chatHistory = new ConcurrentHashMap<>();
    // 新增：存储每个用户所在的群组
    private final ConcurrentHashMap<String, String> userGroupMap = new ConcurrentHashMap<>();
    // 获取单例实例 SessionGroup
    public static SessionGroup inst () {
        return singleInstance;
    }
    // 关闭所有会话，遍历所有通道组，逐个关闭
    public void shutdownGracefully () {
        Iterator<ChannelGroup> groupIterator = groupMap.values().iterator();
        while (groupIterator.hasNext()) {
            ChannelGroup group = groupIterator.next();
            group.close();
        }
    }
    public void sendToOthers(Map<String, String> result, SocketSession s) {
        String group = s.getGroup();
        ChannelGroup groupChannels = groupMap.get(group);
        if (groupChannels == null) return;
// 保存聊天记录
        saveChatHistory (group, result);
        String json = new Gson().toJson(result);
        String messageWithHeader = addHeader(json);
        Channel selfChannel = s.getChannel();
// 遍历所有通道，排除自己后发送（更安全的方式）
        groupChannels.forEach (channel -> {
            if (!channel.equals (selfChannel)) {
                channel.writeAndFlush (new TextWebSocketFrame (messageWithHeader));
            }
        });
    }
    // 新增：保存聊天记录的方法
    private void saveChatHistory (String group, Map<String, String> message) {
        chatHistory.computeIfAbsent (group, k -> new ArrayList<>()).add (message);
    }
    // 新增：获取聊天记录的方法
    public List<Map<String, String>> getChatHistory (String group) {
        return chatHistory.getOrDefault (group, new ArrayList<>());
    }
    // 添加新会话到组，session 新会话
    public void addSession (SocketSession session) {
        String groupName = session.getGroup ();
        String userId = session.getSessionId ();
        if (StringUtils.isEmpty (groupName)) {
// 组为空，直接返回
            return;
        }
// 检查用户是否已经在该群组中
        String existingGroup = userGroupMap.get (userId);
        if (existingGroup != null && existingGroup.equals (groupName)) {
            return;
        }
// 如果用户已经在其他群组中，先从原群组移除
        if (existingGroup != null) {
            ChannelGroup oldGroup = groupMap.get (existingGroup);
            if (oldGroup != null) {
                oldGroup.remove (session.getChannel ());
                AtomicInteger oldCount = groupOnline.get (existingGroup);
                if (oldCount != null && oldCount.decrementAndGet () > 0) {
                    broadcastOnline (existingGroup, session.getUser ().getNickname (), false);
                } else {
                    groupOnline.remove (existingGroup);
                }
                globalOnline.decrementAndGet ();
            }
        }
        ChannelGroup group = groupMap.get(groupName);
        if (null == group) {
            group = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
            groupMap.put(groupName, group);
        }
        group.add(session.getChannel());
// 更新用户所在的群组
        userGroupMap.put (userId, groupName);
// 加入时计数（不修改原有逻辑)
        groupOnline.computeIfAbsent (groupName, k -> new AtomicInteger (0)).incrementAndGet ();
        globalOnline.incrementAndGet ();
// 广播在线人数更新给所有在该聊天室的用户
        broadcastOnline (groupName, session.getUser ().getNickname (), true);
// 发送聊天记录给新用户
        sendChatHistory (session, groupName);
    }
    // 新增：发送聊天记录给新用户的方法
    private void sendChatHistory (SocketSession session, String group) {
        List<Map<String, String>> history = getChatHistory (group);
        Gson gson = new Gson ();
        for (Map<String, String> message : history) {
            String json = gson.toJson (message);
            String messageWithHeader = addHeader (json);
            session.getChannel ().writeAndFlush (new TextWebSocketFrame (messageWithHeader));
        }
    }
    // 关闭连接，关闭前发送一条通知消息
    public void closeSession (SocketSession session, String echo) {
        String group = session.getGroup ();
        if (group != null) {
            ChannelGroup groupChannels = groupMap.get (group);
            if (groupChannels != null) {
                groupChannels.remove (session.getChannel ());
                AtomicInteger count = groupOnline.get (group);
                if (count != null && count.decrementAndGet () > 0) {
                    broadcastOnline (group, session.getUser ().getNickname (), false);
                } else {
                    groupOnline.remove (group);
                }
                globalOnline.decrementAndGet ();
            }
            userGroupMap.remove (session.getSessionId ());
        }
        String messageWithHeader = addHeader (echo);
        ChannelFuture sendFuture = session.getChannel ().writeAndFlush (new TextWebSocketFrame (messageWithHeader));
        sendFuture.addListener (future -> {
            int finalCount = groupOnline.getOrDefault (group, new AtomicInteger (0)).get ();
            System.out.printf("【%s】离开群组[%s]，当前在线：%d人\n",
                    session.getUser().getNickname(),
                    group,
                    finalCount
            );
        });
    }
    //ctx 上下文，msg 待发送的消息
    public void sendMsg (ChannelHandlerContext ctx, String msg) {
        String messageWithHeader = addHeader (msg);
        ChannelFuture sendFuture = ctx.writeAndFlush (new TextWebSocketFrame (messageWithHeader));
        sendFuture.addListener (f -> {// 发送监听
            System.out.println ("对所有发送完成：" + msg);
        });
    }
    public void sendEnterNotice (SocketSession newUser, String noticeMsg) {
        String groupName = newUser.getGroup ();
        ChannelGroup group = groupMap.get (groupName);
        if (group == null || group.size () == 0) return; // 空群组不通知
        Channel selfChannel = newUser.getChannel ();
        Map<String, String> notice = new HashMap<>();
        notice.put ("type", "enter"); // 新增通知类型
        notice.put ("sendUser", newUser.getUser ().getNickname ());
        notice.put ("msg", noticeMsg); // 可自定义通知内容（如 "进入了群"）
        notice.put ("group", groupName); // 带上聊天室信息
// 保存聊天记录
        saveChatHistory (groupName, notice);
        String json = new Gson().toJson(notice);
        String messageWithHeader = addHeader(json);
// 遍历群组发送通知（排除自己）
        group.forEach (channel -> {
            if (!channel.equals (selfChannel)) {
                channel.writeAndFlush (new TextWebSocketFrame (messageWithHeader));
            }
        });
    }
    // 新增：获取人数（供前端 / 控制台使用
    public int getGroupOnline (String group) {
        return groupOnline.getOrDefault (group, new AtomicInteger (0)).get ();
    }
    // 新增：私有广播方法（复用原有发送逻辑）
    // 新增：私有广播方法（复用原有发送逻辑）
    private void broadcastOnline(String group, String username, boolean isJoin) {
        int count = getGroupOnline(group); // 已包含原子操作
        // 修改：去掉格式说明符中间的空格
        System.out.printf("广播 [%s] 人数：%d（用户 %s %s）%n",
                group,
                count,
                username,
                isJoin ? "加入" : "离开");
        Map<String, String> msg = new HashMap<>();
        msg.put("type", "online");
        msg.put("group", group);
        msg.put("count", String.valueOf(getGroupOnline(group)));
        msg.put("user", username);
        msg.put("action", isJoin ? "join" : "leave");
        // 添加 isSwitch 字段
        msg.put("isSwitch", String.valueOf(!isJoin && userGroupMap.containsValue(group)));
        // 复用原有发送逻辑（不修改 sendToOthers）
        sendToGroup(group, msg, null); // 发送给全群组（包括自己）
        System.out.println("send to all");
    }
    // 新增
    private void sendToGroup (String group, Map<String, String> msg, SocketSession exclude) {
        System.out.println ("send to group");
        ChannelGroup groupChannels = groupMap.get (group);
        if (groupChannels == null) return;
        msg.put ("group", group); // 带上聊天室信息
// 保存聊天记录
        saveChatHistory (group, msg);
        String json = new Gson().toJson(msg);
        String messageWithHeader = addHeader(json);
        groupChannels.forEach(channel -> {
            if (exclude == null || !channel.equals(exclude.getChannel())) {
                channel.writeAndFlush(new TextWebSocketFrame(messageWithHeader));
            }
        });
    }
    // 处理用户切换聊天室的方法
    public void switchSession (SocketSession session, String newGroup) {
        String oldGroup = session.getGroup ();
        if (oldGroup != null) {
            ChannelGroup oldGroupChannels = groupMap.get (oldGroup);
            if (oldGroupChannels != null) {
                oldGroupChannels.remove (session.getChannel ()); // 移除连接
// 无论原群组是否有人，强制发送切换通知
                sendSwitchNotice (session, oldGroup, newGroup); // 新增这行！
                AtomicInteger oldCount = groupOnline.get (oldGroup);
                if (oldCount != null) {
                    oldCount.decrementAndGet ();
                    if (oldCount.get () <= 0) { // 人数 <=0 时清理群组
                        groupMap.remove (oldGroup);
                        groupOnline.remove (oldGroup);
                    }
                }
            }
        }
        ChannelGroup newGroupChannels = groupMap.get(newGroup);
        if (newGroupChannels == null) {
            newGroupChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
            groupMap.put(newGroup, newGroupChannels);
        }
        newGroupChannels.add(session.getChannel());
// 更新用户所在的群组
        userGroupMap.put (session.getSessionId (), newGroup);
        session.setGroup (newGroup);
// 加入时计数
        groupOnline.computeIfAbsent (newGroup, k -> new AtomicInteger (0)).incrementAndGet ();
        globalOnline.incrementAndGet ();
// 广播在线人数更新给所有在该聊天室的用户
        broadcastOnline (newGroup, session.getUser ().getNickname (), true);
// 发送聊天记录给新用户
        sendChatHistory (session, newGroup);
    }
    // 新增：发送切换通知
    private void sendSwitchNotice (SocketSession session, String oldGroup, String newGroup) {
        ChannelGroup oldGroupChannels = groupMap.get (oldGroup);
        if (oldGroupChannels == null) return;
        Map<String, String> notice = new HashMap<>();
        notice.put ("type", "switch");
        notice.put ("sendUser", session.getUser ().getNickname ());
        notice.put ("oldGroup", oldGroup);
        notice.put ("newGroup", newGroup);
        notice.put ("group", oldGroup); // 带上原聊天室信息
// 保存聊天记录
        saveChatHistory (oldGroup, notice);
        String json = new Gson().toJson(notice);
        String messageWithHeader = addHeader(json);
        oldGroupChannels.forEach(channel -> {
            if (!channel.equals(session.getChannel())) {
                channel.writeAndFlush(new TextWebSocketFrame(messageWithHeader));
            }
        });
    }
    // 修改 addHeader 方法（使用Base64编码避免特殊字符问题）
    private String addHeader(String message) {
        int type = 1;
        String encoded = Base64.getEncoder().encodeToString(message.getBytes(StandardCharsets.UTF_8));
        return type + "|" + encoded.length() + "|" + encoded;
    }

    // 新增 获取group
    public ChannelGroup getGroup (String group) {
        return groupMap.get (group);
    }
}